# -*- coding: utf-8 -*-
# created on 2016/5/19

from mathsolver.functions.base import *
from sympy import N, sympify, zoo, degree, Mul
from sympy.core.relational import Relational
from random import randint
from mathsolver.functions.root import BasicJisuan
from mathsolver.functions.sympy_utils import get_all_child
from mathsolver.functions.mathematica.mathematicaSolve import MathematicaSolve, MathematicaFindinstance


class ShuYuShiTof001(BaseFunction):
    """
    ShuYuShiTof001().solver(BaseEq(["(9)/(4)*(m)**(2)-m+(1)/(9)","(((3)/(2)*m-(1)/(3)))**(2)"]), ["因式分解"])
    ShuYuShiTof001().solver(BaseEq(['x**2 - 1', '(x+1)*(x -1)']),["因式分解"])
    ShuYuShiTof001().solver(BaseEq(['0.008', '8*((10)**(2))']), [])
    ShuYuShiTof001().solver(BaseEq(["(-8)**(1/3)","-2"]),[])
    ShuYuShiTof001().solver(BaseEq(["((-3))**(2)/(((-(1)/(3))))","-27"]), [])
    """

    def check_calculate(self, number, poly):
        new_number = poly.simplify()
        if new_number == number:
            self.steps.append(["", "%s = %s = %s" % (new_latex(poly), new_latex(number), new_latex(number))])
            return True
        else:
            self.steps.append(["", "%s = %s \\ne %s" % (new_latex(poly), new_latex(new_number), new_latex(number))])
            return False

    @staticmethod
    def _print(f1, f2):
        if str(f1) == str(f2):
            return new_latex(f1)
        else:
            return "%s = %s" % (new_latex(f1), new_latex(f2))

    def solver(self, *args):
        f1, f2 = args[0].sympify()
        subs = args[1]
        if f2.has(sympify("zhenf")):
            answer = False

        elif "因式分解" in subs or "分解因式" in subs:
            if not f2.is_Mul and not f2.is_Pow:
                answer = False
                self.steps.append(["", "右边不是整式积的形式，故选项错误"])
            else:
                factor = f1.expand().factor()
                if str(factor) != str(f2):
                    answer = False
                    self.steps.append(["", "%s = %s \\ne %s" % (new_latex(f1), new_latex(factor), new_latex(f2))])
                else:
                    answer = True
                    self.steps.append(["", "%s = %s = %s" % (new_latex(f1), new_latex(factor), new_latex(f2))])

        elif "一元一次方程" in subs:
            f = f1 - f2
            answer = False
            if len(f.free_symbols) > 1:
                self.steps.append(["", "%s有%s个变量，所以不是一元一次方程" %
                                   (self.output_eq([f1, f2]), len(f.free_symbols))])
            elif degree(f) == 1 and not get_all_child(f, lambda xx: xx.is_Pow and xx.args[1] < 1 and len(
                    xx.args[0].free_symbols) > 0):
                self.steps.append(["", "%s是一元一次方程" % self.output_eq([f1, f2])])
                answer = True

        elif "二元一次方程" in subs:
            f = f1 - f2
            answer = False
            symbols = list(f.free_symbols)
            inter = Mul._from_args(symbols)
            if len(symbols) != 2:
                self.steps.append(["", "%s有%s个变量，所以不是二元一次方程" %
                                   (self.output_eq([f1, f2]), len(symbols))])
            elif degree(f, symbols[0]) == 1 and degree(f, symbols[1]) == 1 and \
                    not get_all_child(f, lambda xx: xx.is_Pow and xx.args[1] < 1 and len(xx.args[0].free_symbols) > 0) and \
                    not get_all_child(f, lambda xx: xx.is_Mul and xx.has(inter)):
                self.steps.append(["", "%s是一元一次方程" % self.output_eq([f1, f2])])
                answer = True

        elif "一元二次方程" in subs:
            f = (f1 - f2).expand().simplify()
            answer = False
            if len(f.free_symbols) > 1:
                self.steps.append(["", "%s有%s个变量，所以不是一元二次方程" %
                                   (self.output_eq([f1, f2]), len(f.free_symbols))])
            elif degree(f) == 2 and not get_all_child(f, lambda xx: xx.is_Pow and xx.args[1] < 1 and len(
                    xx.args[0].free_symbols) > 0):
                self.steps.append(["", "%s是一元二次方程" % self.output_eq([f1, f2])])
                answer = True

        elif len(f1.free_symbols) == 0 and len(f2.free_symbols) == 0:
            new_f1 = BasicJisuan().solver(BasePoly(f1)).output[0].value
            new_f2 = BasicJisuan().solver(BasePoly(f2)).output[0].value
            if str(new_f1) == str(new_f2) or N(f1, 5) == N(f2, 5):
                self.steps.append(["", "%s = %s" % (self._print(f1, new_f1), self._print(new_f2, f2))])
                answer = True
            else:
                self.steps.append(["", "%s \\ne %s" % (self._print(f1, new_f1), self._print(new_f2, f2))])
                answer = False

        elif f1.free_symbols == f2.free_symbols:
            is_equal = []
            new_f1 = f1.cancel().simplify()
            new_f2 = f2.cancel().simplify()
            for i in range(5):
                values = dict([(sym, randint(-10, 10)) for sym in f1.free_symbols])
                v_f1 = new_f1.subs(values).simplify()
                v_f2 = new_f2.subs(values).simplify()
                if v_f1 != zoo and v_f2 != zoo:
                    is_equal.append(v_f1 == v_f2)

            answer = True if all(is_equal) else False
            if answer:
                self.steps.append(["", "%s = %s" % (new_latex(f1), new_latex(f2))])
            else:
                self.steps.append(["", "%s \\ne %s" % (new_latex(f1), new_latex(f2))])

        elif len(f1.free_symbols) > 0:  # and len(f2.free_symbols) ==0:
            new_f1 = f1.simplify()
            if N(new_f1) == N(f2):
                answer = True
                self.steps.append(["", "%s = %s = %s" % (new_latex(f1), new_latex(new_f1), new_latex(f2))])
            else:
                answer = False
                self.steps.append(["", "%s = %s \\ne %s" % (new_latex(f1), new_latex(new_f1), new_latex(f2))])
        else:
            raise ValueError("cannot process the eq type")

        self.output.append(BaseVariable(answer))
        return self


class ShuYuShiTof002(BaseFunction):
    """
    ShuYuShiTof002().solver(BaseIneq(["(-8)**(1/3)",">", "-2"]))
    """

    def solver(self, *args):
        if isinstance(args[0], BaseIneq):
            ineqs = [args[0].sympify()]
        elif isinstance(args[0], BaseEq):
            ineqs = [args[0].sympify()]
        else:
            ineqs = args[0].sympify()

        answers = []
        for item in ineqs:
            if len(item) == 3:
                f1, op, f2 = item
                symbols = list(f1.free_symbols) + list(f2.free_symbols)
                if len(symbols) > 0:
                    ineq = Rel(f1, f2, op)
                    assert not any([isinstance(self.search(sym), Interval) for sym in symbols])
                    symbol_values = dict([(sym, list(self.search(sym))[0]) for sym in symbols])
                    if ineq.subs(symbol_values):
                        answers.append(True)
                    else:
                        answers.append(False)
                        self.steps.append(["", "%s错误" % new_latex(ineq)])
                        break
                else:
                    new_f1 = BasicJisuan().solver(BasePoly(f1)).output[0].value
                    new_f2 = BasicJisuan().solver(BasePoly(f2)).output[0].value
                    ineq = sympify("%s %s %s" % (new_f1, op, new_f2))
                    assert ineq.is_Boolean
                    answers.append(ineq is True)
            else:
                f1, f2 = item
                symbols = list(f1.free_symbols) + list(f2.free_symbols)
                if len(symbols) > 0:
                    eq = Eq(f1, f2)
                    assert not any([isinstance(self.search(sym), Interval) for sym in symbols])
                    if len(symbols) == 1:
                        for v in self.search(symbols[0]):
                            symbol_values = {symbols[0]: v}
                            if eq.subs(symbol_values):
                                answers.append(True)
                            else:
                                answers.append(False)
                                self.steps.append(["", "%s错误" % new_latex(eq)])
                                break
                    else:
                        symbol_values = dict([(sym, list(self.search(sym))[0]) for sym in symbols])
                        if eq.subs(symbol_values):
                            answers.append(True)
                        else:
                            answers.append(False)
                            self.steps.append(["", "%s错误" % new_latex(eq)])
                            break
                else:
                    answers.append(f1 == f2)

        if answers:
            self.output.append(BaseVariable(all(answers)))
        return self


class ShuYuShiTof003(BaseFunction):
    def solver(self, *args):
        # symbols = args[0].free_symbols()
        assert self.known["inequations"]
        if isinstance(args[0], BaseIneq):
            ineqs = [args[0].sympify()]
        else:
            ineqs = args[0].sympify()

        try:
            ans = MathematicaFindinstance().solver(BaseIneqs(self.known["inequations"]), BaseNumber(10)).output[0].value
        except Exception:
            self.output.append(BaseVariable(False))
            return self

        key, value = list(ans.items())[0]
        if isinstance(key, tuple):
            symbol_values = [list(zip(key, v)) for v in value]
        else:
            symbol_values = [{key: v} for v in value]

        for ineq in ineqs:
            rel = Rel(ineq[0], ineq[2], ineq[1])
            for symbol_value in symbol_values:
                v = rel.subs(symbol_value)
                if isinstance(v, Relational):
                    v = v.simplify()
                if not v:
                    self.output.append(BaseVariable(False))
                    return self

        self.output.append(BaseVariable(True))
        self.label.add("判断不等式是否正确")
        return self


class ShuYuShiTof004(BaseFunction):
    def solver(self, *args):
        assert self.known["inequations"]
        ans1 = MathematicaSolve().solver(args[0]).output[0].value
        ans2 = MathematicaSolve().solver(BaseIneqs(self.known["inequations"])).output[0].value

        if ans1 == ans2:
            self.output.append(BaseVariable(True))
        else:
            self.output.append(BaseVariable(False))

        return self


class TofIneqs(ShuYuShiTof002):
    pass


class TofEqs(BaseFunction):
    def solver(self, *args):
        answers = []
        for f1, f2 in args[0].sympify():
            symbols = list(f1.free_symbols) + list(f2.free_symbols)
            if len(symbols) > 0:
                eq = Eq(f1, f2)
                assert not any([isinstance(self.search(sym), Interval) for sym in symbols])
                symbol_values = dict([(sym, list(self.search(sym))[0]) for sym in symbols])
                if eq.subs(symbol_values):
                    answers.append(True)
                else:
                    answers.append(False)
                    self.steps.append(["", "%s错误" % new_latex(eq)])
                    break
            else:
                answers.append(f1 == f2)

        self.output.append(BaseVariable(all(answers)))
        return self


class ShuYuShiTofrational(BaseFunction):
    def solver(self, *args):
        poly = args[0].sympify().simplify()
        if poly.is_Rational or isinstance(args[0], BaseNumber):
            self.steps.append(["", "%s是有理数" % new_latex(poly)])
            self.output.append(BaseVariable(True))
        else:
            self.steps.append(["", "%s不是有理数" % new_latex(poly)])
            self.output.append(BaseVariable(False))

        self.label.add("有理数的定义")
        return self


class ShuYuShiToffinite(BaseFunction):
    def solver(self, *args):
        poly = args[0].sympify().simplify()
        value = str(N(poly, 10)).rstrip("0")
        if len(value.split(".")[1]) < 9:
            self.steps.append(["", "%s=%s是有限小数" % (new_latex(poly), new_latex(value))])
            self.output.append(BaseVariable(True))
        else:
            self.steps.append(["", "%s=%s不是有限小数" % (new_latex(poly), new_latex(value))])
            self.output.append(BaseVariable(False))

        self.label.add("有限小数的定义")
        return self


class ShuYuShiTofunrational(BaseFunction):
    def solver(self, *args):
        poly = args[0].sympify().simplify()

        if poly.is_Rational or isinstance(args[0], BaseNumber):
            self.steps.append(["", "%s不是无理数" % new_latex(poly)])
            self.output.append(BaseVariable(False))
        else:
            self.steps.append(["", "%s是无理数" % new_latex(poly)])
            self.output.append(BaseVariable(True))

        self.label.add("无理数的定义")
        return self


class ShuYuShiTofminisqrt(BaseFunction):
    def solver(self, *args):
        poly = args[0].sympify()

        new_poly = poly.simplify().cancel()
        if new_poly.is_Pow:
            self.steps.append(["", "%s是最简二次根式" % new_latex(poly)])
            self.output.append(BaseVariable(True))
        else:
            self.steps.append(["", "%s不是最简二次根式" % new_latex(poly)])
            self.output.append(BaseVariable(False))

        self.label.add("最简二次根式")
        return self


class ShuYuShiTofnegative(BaseFunction):
    def solver(self, *args):
        poly = args[0].sympify()
        new_poly = poly.simplify()
        if new_poly > 0:
            self.steps.append(["", "%s不是负数" % new_latex(poly)])
            self.output.append(BaseVariable(False))
        else:
            self.steps.append(["", "%s是负数" % new_latex(poly)])
            self.output.append(BaseVariable(True))

        self.label.add("负数的定义")
        return self


class ShuYuShiTofxiangfan(BaseFunction):
    def solver(self, *args):
        poly1 = args[0].sympify()
        poly2 = args[1].sympify()
        new_poly = (poly1 + poly2).simplify()

        if not new_poly.is_zero:
            self.steps.append(["", "%s与%s不是相反数" % (new_latex(poly1), new_latex(poly2))])
            self.output.append(BaseVariable(False))
        else:
            self.steps.append(["", "%s与%s是相反数" % (new_latex(poly1), new_latex(poly2))])
            self.output.append(BaseVariable(True))

        self.label.add("相反数的定义")
        return self


if __name__ == '__main__':
    pass
